using System;
using System.Data.Common;
using System.Data.SqlClient;
using Smallpointer.Configuration.Common;
using System.Data.OracleClient;
using System.Data.OleDb;

namespace Smallpointer.Data.Common
{
    internal class DataExecuter
    {

    }

    internal class ScriptGenerater
    {
        public static DataParameterItem Publish(ExecuteMode mode, DataMapItem source)
        {
            var temp = new DataParameterItem();
            switch (mode)
            {
                case ExecuteMode.Insert:
                    temp = new Insert(source).Publish();
                    break;
                case ExecuteMode.Delete:
                    break;
                case ExecuteMode.Update:
                    break;
                case ExecuteMode.Select:
                    break;
                case ExecuteMode.CreateTable:
                    break;
                default:
                    throw new ArgumentOutOfRangeException("mode");
            }
            return temp;
        }
        internal abstract class ScriptBase
        {
            public DataMapItem Item { get; set; }

            protected ScriptBase(DataMapItem item)
            {
                Item = item;
                if (string.IsNullOrEmpty(item.Name))
                {
                    throw new ArgumentOutOfRangeException("item", "Invalidate attribute setting,please check your entity config xml");
                }
            }

            public abstract DataParameterItem Publish();
        }
        internal class Insert : ScriptBase
        {
            public Insert(DataMapItem item)
                : base(item)
            {

            }
            public override DataParameterItem Publish()
            {
                var temp = new DataParameterItem { Name = Item.Name };
                if (Item.Properties.Count > 0 && !string.IsNullOrEmpty(temp.Name))
                {
                    var sql = "INSERT INTO [" + temp.Name + "]";
                    string columns = string.Empty, values = string.Empty;
                    var len = Item.Properties.Count;
                    for (int i = 0; i < len; i++)
                    {
                        var property = Item.Properties[i];
                        if (property.isprimary || property.identity)
                        {
                            continue;
                        }
                        if (string.IsNullOrEmpty(property.key) || string.IsNullOrEmpty(property.datatype) || !GenerateUtil.DataTypeModeMatched(property.datatype))
                        {
                            continue;
                        }
                        if (string.IsNullOrEmpty(columns))
                        {
                            columns += property.key;
                            values += "@" + property.key;
                            var paramter = GenerateUtil.CreateDataParameter() as DbParameter;
                            if (paramter != null)
                            {
                                paramter.IsNullable = property.isnull;
                                paramter.ParameterName = "@" + property.key;
                                temp.Parameters.Add(property.key, paramter);
                            }
                            continue;
                        }
                        columns += "," + property.key;
                        values += ",@" + property.key;
                        //temp.Parameters.Add(property.key,new DbParamter(){});
                    }
                    sql = string.Format("{0}({1}) values({2})", sql, columns, values);
                    temp.Sql = sql;
                }

                return temp;
            }
        }
        internal class Delete : ScriptBase
        {
            public Delete(DataMapItem item)
                : base(item)
            {

            }

            public override DataParameterItem Publish()
            {
                return new DataParameterItem();
            }
        }
        internal class Update : ScriptBase
        {
            public Update(DataMapItem item)
                : base(item)
            {

            }

            public override DataParameterItem Publish()
            {
                return new DataParameterItem();
            }
        }
        internal class Select : ScriptBase
        {
            public Select(DataMapItem item)
                : base(item)
            {

            }

            public override DataParameterItem Publish()
            {
                return new DataParameterItem();
            }
        }
        internal class Table : ScriptBase
        {
            public Table(DataMapItem item)
                : base(item)
            {

            }

            public override DataParameterItem Publish()
            {
                return new DataParameterItem();
            }
        }
    }

    internal class GenerateUtil
    {
        public static DataTypeMode DataTypeModeMatcher(string code)
        {
            object temp;
            try
            {
                temp = Enum.Parse(typeof(DataTypeMode), code);
            }
            catch (Exception ex)
            {
                throw new ArgumentOutOfRangeException("Invalidate Parameter for the data property attribute, please check the entity map xml.", ex);
            }

            return temp == null ? DataTypeMode.None : (DataTypeMode)temp;
        }
        public static bool DataTypeModeMatched(string code)
        {
            return DataTypeModeMatcher(code) != DataTypeMode.None;
        }


        public static ConnType ConnTypeModeMatcher(string code)
        {
            object temp;
            try
            {
                temp = Enum.Parse(typeof(ConnType), code);
            }
            catch (Exception ex)
            {
                throw new ArgumentOutOfRangeException("Invalidate Parameter for the data property attribute, please check the entity map xml.", ex);
            }

            return temp == null ? ConnType.None : (ConnType)temp;
        }
        public static bool ConnTypeModeMatched(string code)
        {
            return ConnTypeModeMatcher(code) != ConnType.None;
        }


        public static object CreateDataParameter()
        {
            var reader = new ConfigurationReader();
            var conntype = reader.Appsettings("conntype");
            var type = ConnTypeModeMatcher(conntype);
            object temp = null;
            switch (type)
            {
                case ConnType.None:
                    temp = new SqlParameter();
                    break;
                case ConnType.MsSql:
                    temp = new SqlParameter();
                    break;
                case ConnType.MySql:
                    break;
                case ConnType.Oracle:
                    temp = new OracleParameter();
                    break;
                case ConnType.Access:
                    temp = new OleDbParameter();
                    break;
                case ConnType.Sqlite:
                    break;
                default:
                    throw new ArgumentOutOfRangeException(conntype, "database type is not mathed please change it.");
            }
            return temp;
        }
    }
}